﻿<template>
  <div id="cesiumContainer" style="width: 100%; height: 100vh;"></div>
</template>

<script setup>
import { onMounted } from 'vue';
import {
  Ion,
  Viewer,
  Cartesian3,
  Color,
  PointGraphics,
  LabelGraphics,
  BillboardGraphics,
  CallbackProperty,
  Math as CesiumMath,
  JulianDate,
  ScreenSpaceEventType,
  defined,
  HorizontalOrigin,
  VerticalOrigin,
  LabelStyle,
  HeightReference,
  Material,
  MaterialAppearance,
  EllipseGeometry,
  GeometryInstance,
  Primitive
} from "cesium";
import "cesium/Build/Cesium/Widgets/widgets.css";

onMounted(() => {
  // 设置 Cesium Ion 访问令牌
  Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJhNmQ5NDYyNi1lZTdhLTRiYTItODFiZi1mYzNiYWNjNDFjMzgiLCJpZCI6NTk3MTIsImlhdCI6MTY2MDE4MDAyNX0.bDTaHEah0hRjUyJWz0hyxIL0Fg63awPXV26OmQ5MCdM';

  const viewer = new Viewer('cesiumContainer', {
    animation: false, // 移除动画控件
    timeline: false, // 移除时间轴控件
    geocoder: false, // 移除地理编码控件
    homeButton: false, // 移除主页按钮
    sceneModePicker: false, // 移除场景模式选择器
    selectionIndicator: false, // 移除选择指示器
    fullscreenButton: false, // 移除全屏按钮
    vrButton: false // 移除 VR 按钮
  });

  // ==================== 动画相关变量 ====================
  let startTime = performance.now(); // 动画开始时间

  // ==================== 1. 呼吸动画点标注 ====================
  // 使用 CallbackProperty 创建动态属性
  const breathingSize = new CallbackProperty(function(time, result) {
    const elapsed = (performance.now() - startTime) / 1000; // 经过的秒数
    const breathingFactor = Math.sin(elapsed * 2) * 0.5 + 1; // 0.5-1.5之间变化
    return 15 * breathingFactor; // 基础大小15，动态变化
  }, false);

  viewer.entities.add({
    id: 'breathing-point',
    name: '呼吸动画点',
    position: Cartesian3.fromDegrees(114.0579, 22.5431),
    point: new PointGraphics({
      pixelSize: breathingSize, // 动态大小
      color: Color.RED,
      outlineColor: Color.WHITE,
      outlineWidth: 2,
      heightReference: HeightReference.CLAMP_TO_GROUND
    }),
    label: new LabelGraphics({
      text: '呼吸动画点',
      font: '16pt Arial',
      fillColor: Color.WHITE,
      outlineColor: Color.BLACK,
      outlineWidth: 2,
      style: LabelStyle.FILL_AND_OUTLINE,
      pixelOffset: new Cartesian3(0, -50, 0),
      horizontalOrigin: HorizontalOrigin.CENTER,
      verticalOrigin: VerticalOrigin.BOTTOM
    })
  });

  // ==================== 2. 闪烁动画点标注 ====================
  const blinkingAlpha = new CallbackProperty(function(time, result) {
    const elapsed = (performance.now() - startTime) / 1000;
    const blinkFactor = Math.sin(elapsed * 4) > 0 ? 1.0 : 0.3; // 快速闪烁
    return blinkFactor;
  }, false);

  viewer.entities.add({
    id: 'blinking-point',
    name: '闪烁动画点',
    position: Cartesian3.fromDegrees(113.2278, 23.1291),
    point: new PointGraphics({
      pixelSize: 20,
      color: new CallbackProperty(function(time, result) {
        const elapsed = (performance.now() - startTime) / 1000;
        const alpha = Math.sin(elapsed * 4) > 0 ? 1.0 : 0.3;
        return Color.BLUE.withAlpha(alpha);
      }, false),
      outlineColor: Color.YELLOW,
      outlineWidth: 3,
      heightReference: HeightReference.CLAMP_TO_GROUND
    }),
    label: new LabelGraphics({
      text: '闪烁动画点',
      font: '16pt Arial',
      fillColor: Color.YELLOW,
      outlineColor: Color.BLACK,
      outlineWidth: 2,
      style: LabelStyle.FILL_AND_OUTLINE,
      pixelOffset: new Cartesian3(0, -50, 0),
      horizontalOrigin: HorizontalOrigin.CENTER,
      verticalOrigin: VerticalOrigin.BOTTOM
    })
  });

  // ==================== 3. 颜色渐变动画点标注 ====================
  const gradientColor = new CallbackProperty(function(time, result) {
    const elapsed = (performance.now() - startTime) / 1000;
    const hue = (elapsed * 50) % 360; // 色相循环变化
    return Color.fromHsl(hue / 360, 1.0, 0.5); // HSL颜色空间
  }, false);

  viewer.entities.add({
    id: 'gradient-point',
    name: '颜色渐变点',
    position: Cartesian3.fromDegrees(108.9478, 34.2317),
    point: new PointGraphics({
      pixelSize: 25,
      color: gradientColor,
      outlineColor: Color.WHITE,
      outlineWidth: 2,
      heightReference: HeightReference.CLAMP_TO_GROUND
    }),
    label: new LabelGraphics({
      text: '颜色渐变点',
      font: '16pt Arial',
      fillColor: gradientColor, // 标签颜色也跟着变化
      outlineColor: Color.BLACK,
      outlineWidth: 2,
      style: LabelStyle.FILL_AND_OUTLINE,
      pixelOffset: new Cartesian3(0, -50, 0),
      horizontalOrigin: HorizontalOrigin.CENTER,
      verticalOrigin: VerticalOrigin.BOTTOM
    })
  });

  // ==================== 4. 弹跳动画点标注 ====================
  const bounceOffset = new CallbackProperty(function(time, result) {
    const elapsed = (performance.now() - startTime) / 1000;
    const bounce = Math.abs(Math.sin(elapsed * 3)) * 80; // 弹跳高度0-80像素
    return new Cartesian3(0, -50 - bounce, 0);
  }, false);

  viewer.entities.add({
    id: 'bounce-point',
    name: '弹跳动画点',
    position: Cartesian3.fromDegrees(104.0614, 30.6515), // 成都
    point: new PointGraphics({
      pixelSize: 18,
      color: Color.GREEN,
      outlineColor: Color.DARKGREEN,
      outlineWidth: 3,
      heightReference: HeightReference.CLAMP_TO_GROUND
    }),
    label: new LabelGraphics({
      text: '弹跳动画点',
      font: '16pt Arial',
      fillColor: Color.GREEN,
      outlineColor: Color.BLACK,
      outlineWidth: 2,
      style: LabelStyle.FILL_AND_OUTLINE,
      pixelOffset: bounceOffset, // 动态偏移
      horizontalOrigin: HorizontalOrigin.CENTER,
      verticalOrigin: VerticalOrigin.BOTTOM
    })
  });

  // ==================== 5. 旋转动画Billboard标注 ====================
  // 创建一个简单的箭头图标SVG
  const arrowSvg = `
    <svg width="40" height="40" xmlns="http://www.w3.org/2000/svg">
      <polygon points="20,5 35,25 25,25 25,35 15,35 15,25 5,25" 
               fill="orange" stroke="black" stroke-width="1"/>
    </svg>
  `;
  const arrowDataUri = 'data:image/svg+xml;base64,' + btoa(arrowSvg);

  const rotationAngle = new CallbackProperty(function(time, result) {
    const elapsed = (performance.now() - startTime) / 1000;
    return elapsed * CesiumMath.PI_OVER_TWO; // 每2秒旋转90度
  }, false);

  viewer.entities.add({
    id: 'rotation-billboard',
    name: '旋转Billboard',
    position: Cartesian3.fromDegrees(87.6177, 43.7928),
    billboard: new BillboardGraphics({
      image: arrowDataUri,
      scale: 1.0,
      rotation: rotationAngle, // 动态旋转角度
      pixelOffset: new Cartesian3(0, -20, 0),
      horizontalOrigin: HorizontalOrigin.CENTER,
      verticalOrigin: VerticalOrigin.BOTTOM,
      heightReference: HeightReference.CLAMP_TO_GROUND
    }),
    label: new LabelGraphics({
      text: '旋转动画标注',
      font: '16pt Arial',
      fillColor: Color.ORANGE,
      outlineColor: Color.BLACK,
      outlineWidth: 2,
      style: LabelStyle.FILL_AND_OUTLINE,
      pixelOffset: new Cartesian3(0, -80, 0),
      horizontalOrigin: HorizontalOrigin.CENTER,
      verticalOrigin: VerticalOrigin.BOTTOM
    })
  });

  // ==================== 6. 组合动画标注 ====================
  // 综合多种动画效果的复杂标注
  const complexSize = new CallbackProperty(function(time, result) {
    const elapsed = (performance.now() - startTime) / 1000;
    const sizeFactor = Math.sin(elapsed * 1.5) * 0.3 + 1; // 缓慢的呼吸
    return 20 * sizeFactor;
  }, false);

  const complexColor = new CallbackProperty(function(time, result) {
    const elapsed = (performance.now() - startTime) / 1000;
    const alpha = Math.sin(elapsed * 2) * 0.3 + 0.7; // 透明度变化
    return Color.PURPLE.withAlpha(alpha);
  }, false);

  viewer.entities.add({
    id: 'complex-animation',
    name: '组合动画标注',
    position: Cartesian3.fromDegrees(91.1406, 29.6522),
    point: new PointGraphics({
      pixelSize: complexSize,
      color: complexColor,
      outlineColor: Color.WHITE,
      outlineWidth: 2,
      heightReference: HeightReference.CLAMP_TO_GROUND
    }),
    label: new LabelGraphics({
      text: '组合动画',
      font: '18pt Arial',
      fillColor: new CallbackProperty(function(time, result) {
        const elapsed = (performance.now() - startTime) / 1000;
        const hue = (elapsed * 30) % 360;
        return Color.fromHsl(hue / 360, 0.8, 0.6);
      }, false),
      outlineColor: Color.BLACK,
      outlineWidth: 2,
      style: LabelStyle.FILL_AND_OUTLINE,
      pixelOffset: new CallbackProperty(function(time, result) {
        const elapsed = (performance.now() - startTime) / 1000;
        const wobble = Math.sin(elapsed * 4) * 10; // 左右摆动
        return new Cartesian3(wobble, -60, 0);
      }, false),
      horizontalOrigin: HorizontalOrigin.CENTER,
      verticalOrigin: VerticalOrigin.BOTTOM
    })
  });

  // ==================== 7. 波纹扩散效果（重新实现）====================
  // 创建波纹扩散函数
  function createRippleEffect(viewer, longitude, latitude, radius, color, speed) {
    const instance = new GeometryInstance({
      geometry: new EllipseGeometry({
        center: Cartesian3.fromDegrees(longitude, latitude, 0),
        semiMinorAxis: radius,
        semiMajorAxis: radius,
      }),
    });

    const appearance = new MaterialAppearance({
      material: new Material({
        fabric: {
          uniforms: {
            color: Color.fromCssColorString(color),
            speed: speed,
          },
          source: `
            czm_material czm_getMaterial(czm_materialInput materialInput) {
              czm_material material = czm_getDefaultMaterial(materialInput);
              material.diffuse = 1.5 * color.rgb;
              vec2 st = materialInput.st;
              float dis = distance(st, vec2(0.5, 0.5));
              
              // 创建三道波纹，每道间隔0.3的时间
              float per1 = fract(czm_frameNumber * 0.032 * speed);
              float per2 = fract((czm_frameNumber * 0.032 * speed) - 0.3);
              float per3 = fract((czm_frameNumber * 0.032 * speed) - 0.6);
              
              // 计算每道波纹的透明度
              float pass1 = step(per1 * 0.3, dis) == 0.0? color.a * dis / per1: 0.0;
              float pass2 = step(per2 * 0.3, dis) == 0.0? color.a * dis / per2: 0.0;
              float pass3 = step(per3 * 0.3, dis) == 0.0? color.a * dis / per3: 0.0;
              
              // 实现渐变消失效果
              pass1 = pass1 * (1.0 - per1) * 2.0;
              pass2 = pass2 * (1.0 - per2) * 2.0;
              pass3 = pass3 * (1.0 - per3) * 2.0;
              
              // 取最大值作为最终透明度
              material.alpha = max(max(pass1, pass2), pass3);
              return material;
            }
          `,
        }
      }),
    });

    return viewer.scene.primitives.add(
        new Primitive({
          geometryInstances: instance,
          appearance: appearance
        })
    );
  }

  // 添加三个不同的波纹效果
  // 波纹1 - 哈尔滨 - 青色
  createRippleEffect(viewer, 126.5382, 45.8036, 100000, 'rgba(0, 255, 255, 0.8)', 0.2);

  // 为波纹中心添加标注点和标签
  viewer.entities.add({
    id: 'ripple-center-1',
    name: '哈尔滨波纹中心',
    position: Cartesian3.fromDegrees(126.5382, 45.8036),
    point: new PointGraphics({
      pixelSize: 8,
      color: Color.CYAN,
      outlineColor: Color.WHITE,
      outlineWidth: 2,
      heightReference: HeightReference.CLAMP_TO_GROUND
    }),
    label: new LabelGraphics({
      text: '哈尔滨-波纹扩散',
      font: '14pt Arial',
      fillColor: Color.CYAN,
      outlineColor: Color.BLACK,
      outlineWidth: 2,
      style: LabelStyle.FILL_AND_OUTLINE,
      pixelOffset: new Cartesian3(0, -60, 0),
      horizontalOrigin: HorizontalOrigin.CENTER,
      verticalOrigin: VerticalOrigin.BOTTOM
    })
  });



  // ==================== 设置相机视角 ====================
  /*viewer.camera.setView({
    destination: Cartesian3.fromDegrees(116, 30, 3000000),
    orientation: {
      heading: 0.0,
      pitch: -0.99,
      roll: 0.0
    }
  });*/
  // 使用 flyTo 方法，自动计算最佳视角
  viewer.flyTo(viewer.entities);

  // ==================== 点击事件处理 ====================
  viewer.cesiumWidget.screenSpaceEventHandler.setInputAction(function onLeftClick(event) {
    const pickedObject = viewer.scene.pick(event.position);
    if (defined(pickedObject) && defined(pickedObject.id)) {
      console.log('点击的动画标注:', pickedObject.id.name || pickedObject.id.id);

      // 可以在这里添加点击后的交互效果
      if (pickedObject.id.name) {
        alert(`点击了: ${pickedObject.id.name}`);
      }
    }
  }, ScreenSpaceEventType.LEFT_CLICK);

  // ==================== 动画控制函数 ====================
  // 可以添加暂停/恢复动画的功能
  window.pauseAnimations = function() {
    startTime = performance.now() - (performance.now() - startTime);
  };

  window.resumeAnimations = function() {
    startTime = performance.now();
  };

  // 在控制台输出提示信息
  console.log('标注动画示例已加载！');
  console.log('可以使用 pauseAnimations() 和 resumeAnimations() 来控制动画');
});
</script>

<style>
/* 隐藏页面底部的 Cesium logo 和数据归属 */
.cesium-viewer .cesium-widget-credits {
  display: none !important;
}

/* 隐藏右上角的 Imagery 和 Navigation instructions */
.cesium-viewer .cesium-viewer-toolbar {
  display: none !important;
}
</style>
